package com.mocha.bss.domain.rbac.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.coffee.core.FunctionAuthBO;
import com.mocha.bss.domain.rbac.config.MochaFunctionManager;
import com.mocha.bss.feign.bo.menu.FunctionBO;
import com.mocha.bss.feign.bo.menu.MainMenuBO;
import com.mocha.bss.domain.rbac.repository.MochaRoleFunctionRepository;
import com.mocha.bss.domain.rbac.repository.MochaRoleRepository;
import com.mocha.bss.domain.rbac.repository.MochaRoleUserRepository;
import com.mocha.bss.domain.rbac.repository.entity.RoleEntity;
import com.mocha.bss.domain.rbac.repository.entity.RoleFunctionEntity;
import com.mocha.bss.feign.bo.menu.SubMenuBO;
import com.mocha.bss.rbac.bo.RoleFunctionBO;
import com.mocha.bss.rbac.vo.RoleFunctionVO;
import com.pinghua.mocha.basics.setting.MochaSettings;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: songkui
 * @since: 2023/3/20 17:04
 */
@Service
@AllArgsConstructor
public class MochaRoleFunctionService {

    private final MochaRoleFunctionRepository mochaRoleFunctionRepository;
    private final MochaRoleUserRepository mochaRoleUserService;
    private final MochaRoleRepository mochaRoleService;


    public List<MainMenuBO> findMenuAll(){
        return MochaFunctionManager.getAll();
    }


    /**
     * 获取 觉得所有功能权限
     * @param roleId roleId
     * @return roleFunction
     */
    public RoleFunctionVO findMenuRole(Long roleId) {

        if (roleId == null){
            return RoleFunctionVO.builder()
                    .all(false)
                    .list(findMenuAll())
                    .functionCodes("")
                    .build();
        }

        return doFindMenuRole(roleId);

    }

    private RoleFunctionVO doFindMenuRole(Long roleId) {
        String functionCode = mochaRoleFunctionRepository.functionCodeByRoleId(roleId);
        List<MainMenuBO> mainMenuBOS = findMenuAll();
        RoleFunctionVO roleFunctionVO = new RoleFunctionVO(false, "",  mainMenuBOS);
        if (StrUtil.isEmpty(functionCode)){
            return roleFunctionVO;
        }

        if (functionCode.contains(MochaSettings.ALL)){
            roleFunctionVO.setAll(true);
            roleFunctionVO.setFunctionCodes("");
            return roleFunctionVO;
        }
        roleFunctionVO.setAll(false);
        roleFunctionVO.setFunctionCodes(functionCode);
        return roleFunctionVO;
    }

    public List<FunctionBO> findMenuByRoleId(Integer roleId){
        LambdaQueryWrapper<RoleFunctionEntity> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.select(RoleFunctionEntity::getFunctionCode)
                .eq(RoleFunctionEntity::getRoleId, roleId);
        List<RoleFunctionEntity> list = mochaRoleFunctionRepository.list(lambdaQueryWrapper);
        if (CollectionUtil.isEmpty(list)){
            return ListUtil.empty();
        }

        List<String> functionCode = list.stream().map(RoleFunctionEntity::getFunctionCode).collect(Collectors.toList());
        if (functionCode.contains(MochaSettings.ALL)){
            List<FunctionBO> resList = new ArrayList<>(1);
            resList.add(new FunctionBO(MochaSettings.ALL, MochaSettings.ALL, MochaSettings.ALL, MochaSettings.ALL));
            return resList;
        }
        return MochaFunctionManager.findByFunctionCode(functionCode);
    }


    /**
     *  1, 模糊配置； 比如： 如果该大功能有 修改添加权限 那么就有该大功能更 所有权限 /user/*;
     *  2, 每个功能需要 命名规范； 这样才能做 模糊配置； 比如用户相关功能 路径就用  /user/*  开头；
     * @return  key: roleCode;  value: path
     */
    public Map<String, FunctionAuthBO> findAllRolePathMap(){
        List<RoleEntity> roleList = mochaRoleService.findRolesByAll();
        if (CollectionUtil.isEmpty(roleList)){
            return null;
        }
        Map<String, FunctionAuthBO> map = MapUtil.newHashMap(roleList.size());
        for (RoleEntity roleEntity : roleList){
            List<FunctionBO> functionBOList = findMenuByRoleId(roleEntity.getId());
            map.put(roleEntity.getRoleCode(), functionToPath(functionBOList));
        }

        return map;

    }


    private FunctionAuthBO functionToPath(List<FunctionBO> functionBOS){
        if (CollectionUtil.isEmpty(functionBOS)){
            return null;
        }

        Set<String> patternSet = new HashSet<>();
        for (FunctionBO func : functionBOS){
            patternSet.add(func.getPattern());  // /user/*  开头；
        }
       if (CollectionUtil.isNotEmpty(MochaFunctionManager.getCommonPattern())){
           patternSet.addAll(MochaFunctionManager.getCommonPattern());
       }
        List<String> paths = functionBOS.stream().filter(f -> StrUtil.isNotEmpty(f.getFuncPath()) ? true :false).map(FunctionBO::getFuncPath).collect(Collectors.toList());
        String path = CollectionUtil.isNotEmpty(paths) ?  StrUtil.join(",",  paths) : "";
        String[] pattern = ArrayUtil.toArray(patternSet, String.class);
        return new FunctionAuthBO(path, pattern);
    }


    public void addMenuRole(RoleFunctionBO roleFunctionBO) {
        List<RoleFunctionEntity> list = mochaRoleFunctionRepository.lambdaQuery().eq(RoleFunctionEntity::getRoleId, roleFunctionBO.getRoleId()).list();

        String functionCode = roleFunctionBO.getAll() ? MochaSettings.ALL : roleFunctionBO.getFunctionCode();
        if (CollectionUtil.isNotEmpty(list)){
            RoleFunctionEntity entity = new RoleFunctionEntity();
            entity.setId(list.get(0).getId());
            entity.setFunctionCode(functionCode);
            mochaRoleFunctionRepository.updateById(entity);
        }else {
            RoleFunctionEntity entity = new RoleFunctionEntity();
            entity.setRoleId(roleFunctionBO.getRoleId());
            entity.setFunctionCode(functionCode);
            mochaRoleFunctionRepository.save(entity);
        }

    }

}
